#include "GraphMLExport.h"
#include <list>

using namespace std;


GraphMLExport::GraphMLExport()
{
	mNextID=0;
}

void GraphMLExport::generateOutput(string outputName)
{
	mParentModuleData->debug();

	string fileName = outputName.append(".graphml");

	TiXmlDocument output;
	TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "UTF-8", "" );
	TiXmlElement* graphml = new TiXmlElement( "graphml" );

	graphml->SetAttribute("xmlns", "http://graphml.graphdrawing.org/xmlns");
	graphml->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
	graphml->SetAttribute(" xsi:schemaLocation", "http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd");
	
	output.LinkEndChild(decl);
	output.LinkEndChild(graphml);

	TiXmlElement* key = new TiXmlElement("key");
	key->SetAttribute("attr.name",string("description").c_str());
	key->SetAttribute("attr.type", string("string").c_str());
	key->SetAttribute("for", string("node").c_str());
	key->SetAttribute("id",GML_DESCRIPTION_ID);
	output.LinkEndChild(key);

	TiXmlElement* graph = new TiXmlElement( "graph" );
	string ID = getNextIDStr();
	graph->SetAttribute("id", string("g").append(ID).c_str());
	graph->SetAttribute("edgedefault", "directed");
		
	mModuleIDMap.clear();
	generateModuleDataOutput(graph, mParentModuleData, "" );
	generateEdgeDataOutput(graph, mParentModuleData);

	output.LinkEndChild(graph);
	output.SaveFile( fileName.c_str() );
}

void GraphMLExport::generateModuleDataOutput(TiXmlElement* parentElement, ModuleData* moduleData, string parentID)
{
	list <ModuleData*>* childModules = moduleData->getModuleDataList();
	list <ModuleData*>::const_iterator i;

	TiXmlElement* node = new TiXmlElement("node");
	string nodeID = string("n").append(getNextIDStr());
	if (parentID != "") nodeID = string(parentID).append(string("::").append(nodeID));

	node->SetAttribute("id", nodeID.c_str());

	TiXmlElement* descriptionElement = new TiXmlElement("data");
	descriptionElement->SetAttribute("key", GML_DESCRIPTION_ID);
	TiXmlText* descriptionText = new TiXmlText(moduleData->getName().c_str());
	descriptionElement->InsertEndChild(*descriptionText);
	node->InsertEndChild(*descriptionElement);

	if (!childModules->empty())
	{
		TiXmlElement* graph = new TiXmlElement("graph");
		graph->SetAttribute( "id", string(nodeID).append(":").c_str());
		graph->SetAttribute( "edgedefault", string("directed").c_str());
		
		for(i = childModules->begin() ; i != childModules->end();i++)
		{
			generateModuleDataOutput(graph, (*i), nodeID);
		}
		node->InsertEndChild(*graph);
	}
	
	list<Process*>* processList = moduleData->getProcessList();
	for (list<Process*>::iterator j = processList->begin(); j != processList->end(); j++)
	{
		string processID;
		TiXmlElement* process = new TiXmlElement("node");
		if (parentID == "") processID = string("n").append(getNextIDStr());
		else processID = string(parentID).append("::n").append(getNextIDStr());
		process->SetAttribute("id", processID.c_str());

		TiXmlElement* processDescriptionElement = new TiXmlElement("data");
		processDescriptionElement->SetAttribute("key", GML_DESCRIPTION_ID);
		TiXmlText* processDescriptionText = new TiXmlText((*j)->getName().c_str());
		processDescriptionElement->InsertEndChild(*processDescriptionText);
		process->InsertEndChild(*processDescriptionElement);

		node->InsertEndChild(*process);
	}

	mModuleIDMap[moduleData->getName()] = nodeID;

	parentElement->InsertEndChild(*node);
	
}

void GraphMLExport::generateEdgeDataOutput(TiXmlElement* parentElement, ModuleData* moduleData)
{
	list <ModuleData*>* childModules = moduleData->getModuleDataList();
	if (!childModules->empty())
	{
		TiXmlElement* element = parentElement->FirstChildElement();
		for(list<ModuleData*>::iterator i = childModules->begin() ; i != childModules->end();i++)
		{
			generateEdgeDataOutput(element, (*i));
			element = element->NextSiblingElement();
		}
	}

	list<ChannelData*>* childEdges = moduleData->getChannelDataList();
	for (list<ChannelData*>::iterator j = childEdges->begin(); j != childEdges->end(); j++)
	{
		string edgeID = string("e").append(getNextIDStr());
		TiXmlElement* edge = new TiXmlElement("edge");
		
		
		edge->SetAttribute("id", edgeID.c_str());
		edge->SetAttribute("source", mModuleIDMap[(*j)->getSourceModuleData()->getName()].c_str());
		edge->SetAttribute("target", mModuleIDMap[(*j)->getTargetModuleData()->getName()].c_str());
		parentElement->InsertEndChild(*edge);
	}
	
}

string GraphMLExport::getNextIDStr()
{
	char str[10]; 
	_itoa(mNextID++, str, 10);
	return str;
}